﻿#include "HierarchySearchView.h"

#include "LumDebug.h"
#include "TextViewItemDelegate.h"

using BaseClass = ObjectTreeView;

struct HierarchySearchView::HierarchySearchViewData {
    QString searchKeywords;
    QString searchClassName;
};

enum {
    HighlightTextRole = Qt::UserRole +100
};

HierarchySearchView::~HierarchySearchView() { }

HierarchySearchView::HierarchySearchView(QWidget *parent) : BaseClass{parent} {
    d.reset(new HierarchySearchViewData);

    const auto delegate_name = new TextViewItemDelegate;
    delegate_name->setHighlightTextColor(QColor("#00677C"), HighlightTextRole);
    setItemDelegateForColumn(0, delegate_name);

    const auto delate_className = new TextViewItemDelegate;
    delate_className->setHighlightTextColor(QColor("#800080"), HighlightTextRole);
    setItemDelegateForColumn(1, delate_className);
}

int HierarchySearchView::searchObject(const QString &keywords, const QString &className) {
    d->searchKeywords = keywords;
    d->searchClassName = className;
    const auto& result = innerSearchItem(model()->invisibleRootItem(), keywords, className);
    return result;
}

int HierarchySearchView::innerSearchItem(QStandardItem *item, const QString &keywords, const QString &className) {
    const auto IsItemMatched = [=](QStandardItem* item) {
        if(keywords.trimmed().isEmpty() && className.trimmed().isEmpty()) {
            return true;
        }
        const auto &object_name = item->data(Qt::DisplayRole).toString();
        const auto object = item->data(Qt::UserRole).value<QPointer<QObject>>();
        if (!keywords.trimmed().isEmpty()) {
            return object_name.contains(keywords);
        }
        if (!className.isEmpty() && object) {
            return object->inherits(qPrintable(className));
        }
        return false;
    };

    const auto SetItemVisible = [&](QStandardItem* item, bool visible) {
        const auto parent = item->parent();
        setRowHidden(item->row(), parent ? item->parent()->index() : QModelIndex(), !visible);
        if (visible && item->parent()) {
            expand(parent->index());
        }
    };

    auto result = 0;

    auto contains = false;
    const auto& row_count = item->rowCount();
    for (int row = 0; row < row_count; ++row) {
        const auto name_item = item->child(row, 0);
        const auto class_item = item->child(row, 1);

        bool matched = IsItemMatched(name_item);
        if (matched) {
            result += 1;
            name_item->setData(d->searchKeywords, HighlightTextRole);
            class_item->setData(d->searchClassName, HighlightTextRole);
        }

        const auto &child_result = innerSearchItem(name_item, keywords, className);
        result += child_result;

        if (matched || child_result > 0) {
            contains = true;
        }
    }

    //const auto& text = item->text();
    if (IsItemMatched(item)) {
        SetItemVisible(item, true);     
    } else {
        SetItemVisible(item, contains);
    }

    return result;
}
